#pragma once

#include<iostream>
#include<poll.h>
#include"Log.hpp"
#include"Sock.hpp"


#define FD_NONE -1

class Poll
{
public:
    static const int nfds = 100;
public:
    Poll(const uint16_t port = 8080) :_port(port) ,_nfds(nfds)
    {
        _listensock = Sock::Socket();
        Sock::Bind(_listensock, _port);
        Sock::Listen(_listensock);
        logMessage(DEBUG, "%s", "creat base socket success!");

        _fds = new struct pollfd[_nfds];
        for(int i = 0; i < _nfds; i++)
        {
            _fds[i].fd = FD_NONE;
            _fds[i].events = _fds[i].revents = 0;
        }
        _fds[0].fd = _listensock;
        _fds[0].events = POLLIN;

        _timeout = 1000;
    }

    void Start()
    {
        while(true)
        {
            int n = poll(_fds, _nfds, _timeout);
            switch(n)
            {
                case 0:
                    logMessage(DEBUG, "%s", "time out...");
                    break;
                case 1:
                    logMessage(WARNING, "select error: %d : %s", errno, strerror(errno));
                    break;
                default:
                    HandlerEvent();
                    break;
            }
        }
    }

    ~Poll()
    {
        if(_listensock >= 0) 
            close(_listensock);
        if(_fds) delete [] _fds;
    }

private:
    void HandlerEvent()
    {
        for(int i = 0; i < _nfds; i++)
        {
            //1.去掉不合法的fd
            if(_fds[i].fd == FD_NONE) continue;
            //2.
            if(_fds[i].revents & POLLIN)
            {
                if(_fds[i].fd == _listensock) Accepter();
                else Recver(i);
            }
        }
    }

    void Accepter()
    {
        std::string clientip;
        uint16_t clientport;

        int sock = Sock::Accept(_listensock, &clientip, &clientport);
        if(sock < 0)
        {
            logMessage(WARNING, "accept error");
            return;
        }
        logMessage(DEBUG, "get a new line success : [%s:%d] : %d", clientip.c_str(), clientport, sock);
        int pos = 1;
        for(; pos < _nfds; pos++)
        {
            if(_fds[pos].fd == FD_NONE) break;
        }
        if(pos == _nfds)
        {
            //可以扩容
            logMessage(WARNING, "%s:%d", "poll server already full，close: %d", sock);
            close(sock);
        }
        else
        {
            _fds[pos].fd = sock;
            _fds[pos].events = POLLIN;
        }
    }

    void Recver(int pos)
    {
        logMessage(DEBUG, "message in, get IO event: %d", _fds[pos]);
        char buffer[1024];
        int n = recv(_fds[pos].fd, buffer, sizeof buffer - 1, 0);
        if(n > 0)
        {
            buffer[n] = 0;
            logMessage(DEBUG, "client[%d]# %s", _fds[pos].fd, buffer);
        }
        else if(n == 0)
        {
            logMessage(DEBUG, "client[%d] quit, me too...", _fds[pos].fd);
            close(_fds[pos].fd);
            _fds[pos].fd = FD_NONE;
            _fds[pos].events = 0;
        }
        else
        {
            logMessage(WARNING, "%d sock recv error, %d : %s", _fds[pos].fd, errno, strerror(errno));
            close(_fds[pos].fd);
            _fds[pos].fd = FD_NONE;
            _fds[pos].events = 0;
        }
    }

private:
    uint16_t _port;
    int _listensock;
    struct pollfd *_fds;
    int _nfds;
    int _timeout;

};